package com.renfei.multimediatask.ui.task11.scale;

import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.Surface;

import com.renfei.multimediatask.R;
import com.renfei.multimediatask.base.BaseActivity;
import com.renfei.multimediatask.interf.OnSurfaceCreateLinstener;
import com.renfei.multimediatask.util.OpenGlUtils;
import com.renfei.multimediatask.util.glutils.Rotation;
import com.renfei.multimediatask.util.glutils.TextureRotationUtil;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import butterknife.BindView;

import static com.renfei.multimediatask.util.CameraUtils.choosePreviewSize;

/**
 * 视频发生形变， 原因是，surfaceTexture的宽度是屏幕宽度，
 *
 * 摄像头预览尺寸比如是 1280*720 的 ，   surfaceText预览宽度是1184*1080
 *
 *
 *
 * 当前摄像头预览 直接渲染在了 surfaceTexture上
 *
 * 我们无法获取到相机输出尺寸，， 这个功能有想法在实现
 */
public class OpenglCameraScaleTexturePreviewActivity extends BaseActivity implements SurfaceTexture.OnFrameAvailableListener {

    private static final String TAG = "OpenglCamera";
    @BindView(R.id.glSurfaceView)
    GLSurfaceView glSurfaceView;
    Camera camera;


    private int cameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;

    private CameraPreviewRender cameraPreviewRender;


    @Override
    protected int getLayoutId() {
        return R.layout.activity_opengl_camera_preview;
    }

    @Override
    protected void initListener() {
        glSurfaceView.setEGLContextClientVersion(2);
        cameraPreviewRender = new CameraPreviewRender(new WeakReference<>(this));
        cameraPreviewRender.setOnSurfaceCreateLinstener(new OnSurfaceCreateLinstener() {
            @Override
            public void onSurfaceCreate(SurfaceTexture surfaceTexture) {
                Log.e(TAG, "CameraPreviewRender: onSurfaceCreate");
                surfaceTexture.setOnFrameAvailableListener(OpenglCameraScaleTexturePreviewActivity.this);
                try {
                    camera.setPreviewTexture(surfaceTexture);
                    camera.startPreview();
                    Log.e(TAG, "camera: startPreview");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        glSurfaceView.setRenderer(cameraPreviewRender);
        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

    }

    @Override
    protected void onResume() {
        super.onResume();
        if (null == camera) {
            openCamera(1280, 720);
        }
    }


    @Override
    protected void onPause() {
        super.onPause();
        releaseCamera();
    }


    private void openCamera(int width, int height) {

        camera = Camera.open(cameraId);
        if (camera == null) {
            Log.e(TAG, "没有找到前置摄像头，打开默认摄像头");
            camera = Camera.open();    // 默认打开后置摄像头
        }
        if (camera == null) {
            throw new RuntimeException("打开摄像头失败");
        }
        Camera.Parameters parms = camera.getParameters();
        choosePreviewSize(parms, width, height);
        camera.setParameters(parms);
    }

    private void releaseCamera() {
        if (null != camera) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
//        Log.e(TAG, "onFrameAvailable: ");
    }


    static class CameraPreviewRender implements GLSurfaceView.Renderer {
        private static final int FLOAT_SIZE = 4;//一个float数据，占几个字节 一个字节有8位
        private static final int POINT_VEC = 2;//坐标有两个向量 在平面中 只有x,y
        private static int STRIDE = 0;
        private WeakReference<OpenglCameraScaleTexturePreviewActivity> weakReference;


       //   public static final float CUBE[] = {
       //           -1.0f, -1.0f,
       //           1.0f, -1.0f,
       //           -1.0f, 1.0f,
       //           1.0f, 1.0f,
       //   };
        public static final float CUBE[] = {
                -0.9f, -0.9f,
                0.9f, -0.9f,
                -0.9f, 0.9f,
                0.9f, 0.9f,
        };


        private FloatBuffer vertexBuffer;
        private FloatBuffer textureBuffer;

        private int program;
        private int v_Position;//attribute vec4
        private int f_Position;//attribute vec2
        private int sTexture;//uniform
        private int textureTransform;//矩阵
        protected float[] mTextureTransformMatrix=new float[16];


        private int cameraTextureId;

        private SurfaceTexture surfaceTexture;
        private OnSurfaceCreateLinstener onSurfaceCreateLinstener;

        private int refreshCount=0;

        public CameraPreviewRender(WeakReference<OpenglCameraScaleTexturePreviewActivity> weakReference) {
            Log.e(TAG, "CameraPreviewRender: 构造函数");
            this.weakReference = weakReference;

            STRIDE = POINT_VEC * FLOAT_SIZE;

            vertexBuffer = ByteBuffer.allocateDirect(CUBE.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            vertexBuffer.put(CUBE).position(0);

            textureBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.TEXTURE_NO_ROTATION.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            textureBuffer.put(TextureRotationUtil.TEXTURE_NO_ROTATION).position(0);

        }

        public void setOnSurfaceCreateLinstener(OnSurfaceCreateLinstener onSurfaceCreateLinstener) {
            this.onSurfaceCreateLinstener = onSurfaceCreateLinstener;
        }

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            Log.e(TAG, "CameraPreviewRender: onSurfaceCreated");


            String vertexShaderSource = OpenGlUtils.readShaderFromRawResource(weakReference.get(), R.raw.camera_preview_scale_vertex_shader);
            String fragmentShaderSource = OpenGlUtils.readShaderFromRawResource(weakReference.get(), R.raw.camera_preview_scale_fragment_shader);


            program = OpenGlUtils.createProgram(vertexShaderSource, fragmentShaderSource);


            v_Position = GLES20.glGetAttribLocation(program, "v_Position");
            OpenGlUtils.checkLocation(v_Position, "v_Position");
            f_Position = GLES20.glGetAttribLocation(program, "f_Position");
            OpenGlUtils.checkLocation(f_Position, "f_Position");
            sTexture = GLES20.glGetUniformLocation(program, "sTexture");
            OpenGlUtils.checkLocation(sTexture, "sTexture");
            textureTransform=GLES20.glGetUniformLocation(program,"textureTransform");
            OpenGlUtils.checkLocation(textureTransform,"textureTransform");

            //创建摄像头纹理ID
            createCameraTextureID();

        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
            Log.e(TAG, "CameraPreviewRender: onSurfaceChanged  width    "+width+"   height  "+height);

            adjustImageScaling();
        }

        @Override
        public void onDrawFrame(GL10 gl) {

            surfaceTexture.updateTexImage();//调用才会刷新

            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
            GLES20.glClearColor(0.1f, 0.4f, 0.7f, 1.0f);

            GLES20.glUseProgram(program);


            surfaceTexture.getTransformMatrix(mTextureTransformMatrix);

            if (refreshCount<1){
                for (int i = 0; i < mTextureTransformMatrix.length; i++) {

                    Log.e(TAG, "mTextureTransformMatrix: "+i+"  =   "+mTextureTransformMatrix[i]);

                }
            }

            GLES20.glUniformMatrix4fv(textureTransform, 1, false, mTextureTransformMatrix, 0);


            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTextureId);
            GLES20.glUniform1i(sTexture, 0);

            GLES20.glEnableVertexAttribArray(v_Position);
            GLES20.glVertexAttribPointer(v_Position, POINT_VEC, GLES20.GL_FLOAT, false, 0, vertexBuffer);
            GLES20.glEnableVertexAttribArray(f_Position);
            GLES20.glVertexAttribPointer(f_Position, POINT_VEC, GLES20.GL_FLOAT, false, 0, textureBuffer);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);

            refreshCount++;
        }


        /**
         *
         */
        private void createCameraTextureID() {
            int[] textures = new int[1];
            GLES20.glGenTextures(1, textures, 0);
            cameraTextureId = textures[0];

            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTextureId);

            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);

            surfaceTexture = new SurfaceTexture(cameraTextureId);
            if (null != onSurfaceCreateLinstener) {
                onSurfaceCreateLinstener.onSurfaceCreate(surfaceTexture);
            }

        }
        /**
         * 根据方向调整对应的 纹理顶点坐标
         */
        private void adjustImageScaling() {

            //摄像头 前置 或者 后置
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            Camera.getCameraInfo(weakReference.get().cameraId, cameraInfo);


            //是否前置
            boolean isFacing_front = weakReference.get().cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT;

            adjustSize(cameraInfo.orientation, isFacing_front, !isFacing_front);
        }

        protected void adjustSize(int rotation, boolean flipHorizontal, boolean flipVertical) {
            float[] textureCords = TextureRotationUtil.getRotation(Rotation.fromInt(rotation),
                    flipHorizontal, flipVertical);
            float[] cube = CUBE;

            vertexBuffer.clear();
            vertexBuffer.put(cube).position(0);
            textureBuffer.clear();
            textureBuffer.put(textureCords).position(0);
        }
    }

}
